/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package net.jcdev.coolrss.model.dao;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import net.jcdev.coolrss.model.dao.exceptions.IllegalOrphanException;
import net.jcdev.coolrss.model.dao.exceptions.NonexistentEntityException;
import net.jcdev.coolrss.model.dao.exceptions.PreexistingEntityException;
import net.jcdev.coolrss.model.entity.Feed;
import net.jcdev.coolrss.model.entity.Tag;
import net.jcdev.coolrss.model.entity.Entry;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author carlos
 */
public class FeedJpaController {

    public FeedJpaController() {
        emf = Persistence.createEntityManagerFactory("CoolRSSPU");
    }
    private EntityManagerFactory emf = null;

    public EntityManager getEntityManager() {
        return emf.createEntityManager();
    }

    public void create(Feed feed) throws PreexistingEntityException, Exception {
        if (feed.getEntryList() == null) {
            feed.setEntryList(new ArrayList<Entry>());
        }
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Tag tagName = feed.getTagName();
            if (tagName != null) {
                tagName = em.getReference(tagName.getClass(), tagName.getTagName());
                feed.setTagName(tagName);
            }
            List<Entry> attachedEntryList = new ArrayList<Entry>();
            for (Entry entryListEntryToAttach : feed.getEntryList()) {
                entryListEntryToAttach = em.getReference(entryListEntryToAttach.getClass(), entryListEntryToAttach.getEntryId());
                attachedEntryList.add(entryListEntryToAttach);
            }
            feed.setEntryList(attachedEntryList);
            em.persist(feed);
            if (tagName != null) {
                tagName.getFeedList().add(feed);
                tagName = em.merge(tagName);
            }
            for (Entry entryListEntry : feed.getEntryList()) {
                Feed oldFeedLinkOfEntryListEntry = entryListEntry.getFeedLink();
                entryListEntry.setFeedLink(feed);
                entryListEntry = em.merge(entryListEntry);
                if (oldFeedLinkOfEntryListEntry != null) {
                    oldFeedLinkOfEntryListEntry.getEntryList().remove(entryListEntry);
                    oldFeedLinkOfEntryListEntry = em.merge(oldFeedLinkOfEntryListEntry);
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            if (findFeed(feed.getFeedLink()) != null) {
                throw new PreexistingEntityException("Feed " + feed + " already exists.", ex);
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void edit(Feed feed) throws IllegalOrphanException, NonexistentEntityException, Exception {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Feed persistentFeed = em.find(Feed.class, feed.getFeedLink());
            Tag tagNameOld = persistentFeed.getTagName();
            Tag tagNameNew = feed.getTagName();
            List<Entry> entryListOld = persistentFeed.getEntryList();
            List<Entry> entryListNew = feed.getEntryList();
            List<String> illegalOrphanMessages = null;
            for (Entry entryListOldEntry : entryListOld) {
                if (!entryListNew.contains(entryListOldEntry)) {
                    if (illegalOrphanMessages == null) {
                        illegalOrphanMessages = new ArrayList<String>();
                    }
                    illegalOrphanMessages.add("You must retain Entry " + entryListOldEntry + " since its feedLink field is not nullable.");
                }
            }
            if (illegalOrphanMessages != null) {
                throw new IllegalOrphanException(illegalOrphanMessages);
            }
            if (tagNameNew != null) {
                tagNameNew = em.getReference(tagNameNew.getClass(), tagNameNew.getTagName());
                feed.setTagName(tagNameNew);
            }
            List<Entry> attachedEntryListNew = new ArrayList<Entry>();
            for (Entry entryListNewEntryToAttach : entryListNew) {
                entryListNewEntryToAttach = em.getReference(entryListNewEntryToAttach.getClass(), entryListNewEntryToAttach.getEntryId());
                attachedEntryListNew.add(entryListNewEntryToAttach);
            }
            entryListNew = attachedEntryListNew;
            feed.setEntryList(entryListNew);
            feed = em.merge(feed);
            if (tagNameOld != null && !tagNameOld.equals(tagNameNew)) {
                tagNameOld.getFeedList().remove(feed);
                tagNameOld = em.merge(tagNameOld);
            }
            if (tagNameNew != null && !tagNameNew.equals(tagNameOld)) {
                tagNameNew.getFeedList().add(feed);
                tagNameNew = em.merge(tagNameNew);
            }
            for (Entry entryListNewEntry : entryListNew) {
                if (!entryListOld.contains(entryListNewEntry)) {
                    Feed oldFeedLinkOfEntryListNewEntry = entryListNewEntry.getFeedLink();
                    entryListNewEntry.setFeedLink(feed);
                    entryListNewEntry = em.merge(entryListNewEntry);
                    if (oldFeedLinkOfEntryListNewEntry != null && !oldFeedLinkOfEntryListNewEntry.equals(feed)) {
                        oldFeedLinkOfEntryListNewEntry.getEntryList().remove(entryListNewEntry);
                        oldFeedLinkOfEntryListNewEntry = em.merge(oldFeedLinkOfEntryListNewEntry);
                    }
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                String id = feed.getFeedLink();
                if (findFeed(id) == null) {
                    throw new NonexistentEntityException("The feed with id " + id + " no longer exists.");
                }
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void destroy(String id) throws IllegalOrphanException, NonexistentEntityException {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Feed feed;
            try {
                feed = em.getReference(Feed.class, id);
                feed.getFeedLink();
            } catch (EntityNotFoundException enfe) {
                throw new NonexistentEntityException("The feed with id " + id + " no longer exists.", enfe);
            }
            List<String> illegalOrphanMessages = null;
            List<Entry> entryListOrphanCheck = feed.getEntryList();
            for (Entry entryListOrphanCheckEntry : entryListOrphanCheck) {
                if (illegalOrphanMessages == null) {
                    illegalOrphanMessages = new ArrayList<String>();
                }
                illegalOrphanMessages.add("This Feed (" + feed + ") cannot be destroyed since the Entry " + entryListOrphanCheckEntry + " in its entryList field has a non-nullable feedLink field.");
            }
            if (illegalOrphanMessages != null) {
                throw new IllegalOrphanException(illegalOrphanMessages);
            }
            Tag tagName = feed.getTagName();
            if (tagName != null) {
                tagName.getFeedList().remove(feed);
                tagName = em.merge(tagName);
            }
            em.remove(feed);
            em.getTransaction().commit();
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public List<Feed> findFeedEntities() {
        return findFeedEntities(true, -1, -1);
    }

    public List<Feed> findFeedEntities(int maxResults, int firstResult) {
        return findFeedEntities(false, maxResults, firstResult);
    }

    private List<Feed> findFeedEntities(boolean all, int maxResults, int firstResult) {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            cq.select(cq.from(Feed.class));
            Query q = em.createQuery(cq);
            if (!all) {
                q.setMaxResults(maxResults);
                q.setFirstResult(firstResult);
            }
            return q.getResultList();
        } finally {
            em.close();
        }
    }

    public Feed findFeed(String id) {
        EntityManager em = getEntityManager();
        try {
            return em.find(Feed.class, id);
        } finally {
            em.close();
        }
    }

    public Feed findFeedByTitle(String title) {
        EntityManager em = getEntityManager();
        try {
            
            Query query = em.createNamedQuery("Feed.findByFeedTitle", Feed.class);
            query.setParameter("feedTitle", title);
            Feed feed = (Feed) query.getSingleResult();

            return feed;

        } finally {
            em.close();
        }
    }

    public int getFeedCount() {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            Root<Feed> rt = cq.from(Feed.class);
            cq.select(em.getCriteriaBuilder().count(rt));
            Query q = em.createQuery(cq);
            return ((Long) q.getSingleResult()).intValue();
        } finally {
            em.close();
        }
    }

}
